package com.lt.crm.shiro;


import com.lt.crm.pojo.SysRight;
import com.lt.crm.pojo.SysRole;
import com.lt.crm.pojo.SysUser;
import com.lt.crm.service.SysUserService;
import javax.annotation.Resource;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;


import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * 自定义Realm
 */
public class MyShiroRealm extends AuthorizingRealm {// 安全管理器

    @Resource
    SysUserService sysUserService;
    @Resource
    StringRedisTemplate stringRedisTemplate;
    // redis中数据key的前缀
    private String SHIRO_LOGIN_COUNT = "shiro_login_count_";//登陆计数
    private String SHIRO_IS_LOCK = "shiro_is_lock_";//锁定用户登录


    /**
     * 执行授权逻辑
     *
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        // 获得权限信息
        SysUser user = (SysUser) principalCollection.getPrimaryPrincipal();
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        //动态
        SysRole role = user.getRole();
        if (role != null) {
            info.addRole(user.getRole().getRoleName());
            List<SysRight> rights = role.getRights();
            if (rights != null && rights.size() > 0) {
                for (SysRight obj : rights) {
                    info.addStringPermission(obj.getRightCode());
                }
            }
        }
        return info;
    }

    /**
     * 执行认证逻辑
     *
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken)
            throws AuthenticationException {
        // 编写shiro判断逻辑，判断用户名和密码
        // 1、判断用户名
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;//获取身份信息
        String usrName = token.getUsername();
        // 每次访问，登录次数+1
        ValueOperations<String, String> operations = stringRedisTemplate.opsForValue();
        operations.increment(SHIRO_LOGIN_COUNT + usrName, 1);
        // 计数大于5时，设置用户被锁定一个小时，清空登陆计数
        if (Integer.parseInt(operations.get(SHIRO_LOGIN_COUNT + usrName)) > 5) {
            operations.set(SHIRO_IS_LOCK + usrName, "LOCK");
            stringRedisTemplate.expire(SHIRO_IS_LOCK + usrName, 1, TimeUnit.HOURS);
            stringRedisTemplate.delete(SHIRO_LOGIN_COUNT + usrName);//清空登录计数
        }
        //账号禁用
        if ("LOCK".equals(operations.get(SHIRO_IS_LOCK + usrName))) {
            throw new DisabledAccountException();
        }
        SysUser user = sysUserService.getUserByUsrName(usrName);
        if (user == null) {
            // 用户不存在
            throw new UnknownAccountException();//shiro底层会抛出UnknownAccountException
        }
        if (user.getUsrFlag() == null || user.getUsrFlag() == 0) {
            throw new LockedAccountException();//账号锁定
        }
        // 2、判断密码
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(
                user,//身份（根据用户名查询数据库获得的用户）
                user.getUsrPassword(),//凭证（查询数据库获得的密码）
                ByteSource.Util.bytes("czkt"),//加密使用的salt、加盐
                getName());//Realm对象的名称
        // 只获得身份信息
        //assertCredentialsMatch(token, info);//方法对token中的密码何info中的密码进行判断，认证失败抛出异常
        return info;
    }

    //清空当前认证用户权限缓存
    public void  clearMyCachedAuthorizationInfo(){
        clearCachedAuthenticationInfo(SecurityUtils.getSubject().getPrincipals());
    }
}
